#include "LxMemo.h"
#include "ListItem.h"
#include "TxtDelegate.h"
#include "MemoDialog.h"
#include <QScrollBar>
#include <QMouseEvent>
#include <QScroller>
#include <QFileDialog>
#include <QDateTime>
#include <QInputDialog>
#include <QMenu>
#include <QMimeData>
#include <QClipboard>
#include "MessageBox.h"
#include "MessageShower.h"
#include "FolderCreator.h"
#include "Folder.h"
#include "util.h"
#include "db.h"

LxMemo::LxMemo(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	setWindowIcon(QIcon(":/LxMemo/icons/memo.png"));
	setStyleSheet("background-color:transparent;");

	ui.button_forward->setVisible(false);
	ui.button_back->setEnabled(false);

	//deleg->installEventFilter(this);
	auto delegate = new TxtDelegate();
	ui.listWidget->setItemDelegate(delegate);
	ui.listWidget->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
	ui.listWidget->setSelectionBehavior(QAbstractItemView::SelectRows);

	connect(delegate, &TxtDelegate::editFinshed, this, &LxMemo::onEditFinished);
	connect(ui.listWidget, &QListWidget::doubleClicked, this, &LxMemo::onEditMemo);
	connect(ui.listWidget, &QListWidget::customContextMenuRequested, this, &LxMemo::onDeleteMemo);
	connect(ui.listWidget, SIGNAL(clicked(const QModelIndex&)), this, SLOT(onItemEdit(const QModelIndex&)));

	//ui.cycleWidget->setItemDelegate(new TxtDelegate());
	//ui.cycleWidget->setEditTriggers(QAbstractItemView::SelectedClicked);
	//ui.cycleWidget->setSelectionBehavior(QAbstractItemView::SelectRows);

	connect(ui.button_back, &QToolButton::clicked, this, &LxMemo::onBack);
	connect(ui.button_forward, &QToolButton::clicked, this, &LxMemo::onForward);
	connect(ui.button_new_folder, &QToolButton::clicked, this, &LxMemo::onAddFolder);

	//QScroller::grabGesture(ui.cycleWidget, QScroller::LeftMouseButtonGesture);

	//connect(ui.cycleWidget, SIGNAL(clicked(const QModelIndex&)), this, SLOT(onRecycleItemEdit(const QModelIndex&)));

	initDB();
	//loadMemo();

	//ui.listWidget->resize(300, 500);
	//ui.listWidget->show();
	//ui.listWidget->setBackgroundRole(QPalette::Background);
	ui.listWidget->installEventFilter(this);
	ui.listWidget->viewport()->installEventFilter(this);
	ui.listWidget->setMouseTracking(true);
	//ui.cycleWidget->setMouseTracking(true);

	_cc = new ColorChunk(this);
	_cc->hide();

	//_trayIcon = new QSystemTrayIcon(this);
	//_trayIcon->setIcon(QIcon(":/LxMemo/icons/memo.png"));
	//QMenu* menu = new QMenu();
	//auto mui = menu->addAction(QIcon(":/LxMemo/icons/memo.png"), "Show Main UI");
	//auto ext = menu->addAction(QIcon(":/LxMemo/icons/Exit.png"), "Exit");
	//_trayIcon->setContextMenu(menu);
	//_trayIcon->show();

	//connect(mui, &QAction::triggered, this, &LxMemo::ReDisplay);
	//connect(ext, &QAction::triggered, this,
	//    [this] {
	//        for (auto& it : _opendDlg)
	//            it->close();
	//        close();
	//    });

	//std::function<void(QSystemTrayIcon::ActivationReason reason)>
	//    cb = [this](QSystemTrayIcon::ActivationReason reason)
	//{
	//    switch (reason)
	//    {
	//    case QSystemTrayIcon::Unknown:
	//        break;
	//    case QSystemTrayIcon::Context:
	//        break;
	//    case QSystemTrayIcon::DoubleClick:
	//        emit ReDisplay();
	//        break;
	//    case QSystemTrayIcon::Trigger:
	//        break;
	//    case QSystemTrayIcon::MiddleClick:
	//        break;
	//    default:
	//        break;
	//    }
	//};

	//connect(_trayIcon, &QSystemTrayIcon::activated, this, cb);

	std::function<void(const QColor&)> colselCB = [this](const QColor& color)
	{
		if (_currItem) {
			auto meta = qvariant_cast<SharedMeta>(_currItem->data(0));
			auto bytes = meta->PropertyToStream();
			std::unique_ptr<char> data(new char[bytes.size() + 256] { 0 });
			int r = sprintf(data.get(), "update Memo set PROP=\"%s\" where ID=%u;",
				bytes.data(),
				meta->Id());

			bool ret = ExecSQL(db, data.get());
			if (ret) {
				meta->SetColor(color);
				_currItem->setData(0, QVariant::fromValue(meta));

				if (_opendDlg.contains(meta->Id())) {
					auto memo = qSharedPointerCast<Memo>(meta);
					auto dlg = _opendDlg.value(memo->Id());
					dlg->Widget<MemoDialog*>()->SetMemo(memo);
					//dlg->setStyleSheet(tr("background-color: %1;").arg(color.name(QColor::HexRgb)));
					dlg->SetPureStyle(color.name(QColor::HexArgb));
					dlg->Widget<MemoDialog*>()->setStyleSheet(tr("background-color: %1;").arg(color.name(QColor::HexArgb)));
					//dlg->update();
				}
				ui.listWidget->repaint();
			}
		}
	};
	connect(_cc, &ColorChunk::ColorSelected, this, colselCB);

	QDir cache(".");
	bool r = cache.mkdir(".cache");
	if (r) {
		cache.setCurrent(".cache");
		SetFileAttributes((LPCWSTR)cache.absolutePath().unicode(), FILE_ATTRIBUTE_HIDDEN);
	}
#if 1
	QGraphicsDropShadowEffect* shadow_effect = new QGraphicsDropShadowEffect();
	shadow_effect->setOffset(0, 0);

	//阴影颜色
	shadow_effect->setColor(QColor(38, 78, 119, 100));

	//阴影半径
	shadow_effect->setBlurRadius(16);

	setGraphicsEffect(shadow_effect);
#endif
}

LxMemo::~LxMemo()
{
	sqlite3_close_v2(db);
}

void LxMemo::onAddMemo()
{
	//Memo memo;
	addMemo(SharedMemo(new Memo()));
}

void LxMemo::addMemo(SharedMeta memo)
{
	QListWidgetItem* item = new QListWidgetItem();
	//item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);
	item->setData(0, QVariant::fromValue(memo));
	item->setData(1, "MEMO");
	item->setData(Qt::UserRole, memo->Id());

	ui.listWidget->insertItem(0, item);
	auto time = QDateTime::currentDateTime().toString();

	char buffer[512]{ 0 };
	sprintf(buffer,
		R"(insert into Memo (ID, PROP, IN_RECYCLE, TIME, PPATH, TYPE) values(%u, "%s", 0, "%s", "%s", "FILE");)",
		memo->Id(), memo->PropertyToStream().data(), time.toLocal8Bit().data(), _path.path().toLocal8Bit().data());

	ExecSQL(db, buffer);

	QDir dir(tr(".cache"));
	dir.mkdir(tr("%1").arg(QString::number(memo->Id())));
}

struct DelContext
{
	QListWidget* listwidget;
	QModelIndex index;
	uint32_t id;
	sqlite3* db;
};
int cb(void* ctx, int rows, char** data, char**)
{
	int count = atoi(data[0]);
	DelContext* dctx = (DelContext*)ctx;

	if (count == 0) {
		char buffer[128]{ 0 };
		sprintf(buffer, "update Memo set IN_RECYCLE=1 where ID=%u", dctx->id);
		//sprintf(buffer, "delete from Memo where ID=%u", dctx->id);
		bool ret = ExecSQL(dctx->db, buffer);
		if (ret)
			dctx->listwidget->takeItem(dctx->index.row());
	}
	else {
		MessageShower::Start("Folder isn't empty", dctx->listwidget);
	}

	return 0;
}

struct MemoContext
{
	LxMemo* lx;
	SharedMemo memo;

	void(*cb)(LxMemo*, SharedMemo);
};

///从数据库读取memo正文
int loadMemoData(void* lx, int rows, char** rowData, char** colNames)
{
	auto ctx = (MemoContext*)lx;

	QString html = QString::fromLocal8Bit(QByteArray::fromBase64(rowData[0]));
	ctx->memo->SetHtml(html);

	//ctx->lx->showMemo(ctx->memo);
	if (ctx->cb)
		ctx->cb(ctx->lx, ctx->memo);

	return 0;
}

void LxMemo::editItem(const QModelIndex& index, const QPoint& pos)
{
	if (!index.isValid())
		return;
	auto item = ui.listWidget->item(index.row());
	_currItem = item;

	QMenu menu;
	//menu.setFixedWidth(100);
	auto delAction = menu.addAction(QIcon(":/LxMemo/icons/recycle-fill.png"), tr("Delete"));
	auto swapColor = menu.addAction(QIcon(":/LxMemo/icons/eglass-color.png"), tr("Recolor"));

	auto meta = qvariant_cast<SharedMeta>(item->data(0));
	auto type = index.data(1);

	uint32_t id = meta->Id();

	std::function<void(const Path&)> delFolder = [this, id, index](const Path& path)
	{
		auto sql = tr(R"(select count(*) from Memo where PPATH="%1" and IN_RECYCLE=0)").arg(path.path());

		DelContext ctx = { ui.listWidget, index, id, db };
		ExecSQL(db, sql.toLocal8Bit().data(), cb, &ctx);
	};

	std::function<void(bool)> delCB = [this, id, index, delFolder, meta](bool)
	{
		auto endpos = mapToGlobal(QPoint(10, height() / 2 - 30));
		auto startpos = mapToGlobal(QPoint(10, height() / 2 - 30));

		LucencyDialog* dlg = new LucencyDialog(this);
		MessageDialog* msg = new MessageDialog(dlg);
		dlg->setWindowModality(Qt::ApplicationModal);
		dlg->SetPureStyle("rgb(235,229,209)");
		dlg->setAttribute(Qt::WA_DeleteOnClose);
		dlg->SetFixedEnable(false);
		dlg->SetAttribute(~WA_MINIMUM_WINDOW & ~WA_MAXIMUM_WINDOW);
		dlg->SetWidget(msg);
		dlg->show();

		StartOpacityAnimation(dlg, 0, 1);
		StartGeometryAnimation(dlg,
			QRect(startpos, QSize(width() - 20, 10)),
			QRect(endpos, QSize(width() - 20, 60)),
			QEasingCurve::Linear, 100);

		connect(msg, SIGNAL(windowClosed()), dlg, SLOT(close()));

		auto type = index.data(1);
		if (type == "FOLDER")
		{
			auto folder = qSharedPointerCast<Folder>(meta);

			msg->setText(tr("是否删除该目录？"));
			int ok = msg->exec();

			if (ok == QDialog::Accepted) {
				auto path = _path;
				path += folder->name();
				delFolder(path);
			}
		}
		else {
			msg->setText(QString::fromUtf8("是否删除该文件？"));
			int ok = msg->exec();
			if (ok == QDialog::Accepted) {
				char buffer[128]{ 0 };
				sprintf(buffer, "update Memo set IN_RECYCLE=1 where ID=%u", id);
				//sprintf(buffer, "delete from Memo where ID=%u", id);
				bool ret = ExecSQL(db, buffer);
				if (ret) {
					ui.listWidget->takeItem(index.row());
					if (_opendDlg.contains(id))
						_opendDlg.value(id)->close();
					if (_cutMeta && _cutMeta->Id() == id) {
						_cutMeta = nullptr;
						_cutItem = QModelIndex();
					}
				}
			}
		}
	};

	std::function<void(bool)> showfn = [this, index, id](bool)
	{
		if (!_opendDlg.contains(id))
			onEditMemo(index);
		else
		{
			auto dlg = _opendDlg.value(id);
			dlg->close();
			//delete dlg;
			_opendDlg.remove(id);
		}
	};

	std::function<void(bool)> colorCB = [this, item](bool)
	{
		_cc->move(0, height() - _cc->height());
		_cc->resize(width(), _cc->height());
		_cc->show();
	};

	std::function<void(bool)> exportHtml = [this, meta](bool)
	{
		auto memo = qSharedPointerCast<Memo>(meta);
		if (!memo->GetHtml().isEmpty()) {
			this->exportHtml(memo);
		}
		else {
			auto sql = QString("select DATA from Memo where ID=%1").arg(QString::number(memo->Id()));

			MemoContext ctx = { this, memo , [](LxMemo* lm, SharedMemo memo) {lm->exportHtml(memo); } };
			ExecSQL(db, sql.toUtf8().data(), loadMemoData, &ctx);
		}
	};

	std::function<void(bool)> renamefn = [this, index](bool)
	{
		ui.listWidget->edit(index);
	};

	std::function<void(bool)> cutMemofn = [this, meta, index](bool)
	{
		_cutMeta = meta;
		_cutItem = index;
	};

	if (type != "FOLDER") {
		auto showAction = menu.addAction(QIcon(":/LxMemo/icons/show.png"), tr("Show"));
		menu.addSeparator();
		auto cutAction = menu.addAction(QIcon(":/LxMemo/icons/cut.png"), tr("Cut"));
		auto exportAction = menu.addAction(QIcon(":/LxMemo/icons/export.png"), tr("Export"));

		if (_opendDlg.contains(id)) {
			showAction->setIcon(QIcon(":/LxMemo/icons/close_eyes.png"));
			//showAction->setEnabled(false);
		}
		connect(cutAction, &QAction::triggered, this, cutMemofn);
		connect(showAction, &QAction::triggered, this, showfn);
		connect(exportAction, &QAction::triggered, this, exportHtml);
	}
	else {
		auto renameAction = menu.addAction(QIcon(":/LxMemo/icons/rename.png"), tr("Rename"));
		connect(renameAction, &QAction::triggered, this, renamefn);
	}

	connect(delAction, &QAction::triggered, this, delCB);
	connect(swapColor, &QAction::triggered, this, colorCB);

	menu.exec(pos);
}

void LxMemo::editRecycleItem(const QModelIndex& index)
{
	/*
	if (!index.isValid())
		return;
	auto item = ui.cycleWidget->item(index.row());

	QMenu menu;
	//menu.setFixedWidth(100);
	auto rcvAction = menu.addAction(QIcon(":/LxMemo/icons/recovery.png"), tr("Rrecover"));
	auto delAction = menu.addAction(QIcon(":/LxMemo/icons/close.png"), tr("Delete"));

	auto memo = qvariant_cast<SharedMemo>(item->data(0));
	uint32_t id = memo->Id();

	std::function<void(bool)> delCB = [this, index, id](bool)
	{
		char buffer[512]{ 0 };
		sprintf(buffer, "delete from Memo where ID=%u;", id);
		ExecSQL(db, buffer);
		ui.cycleWidget->takeItem(index.row());

		///删除该Memo同时删除所有的图片资源
		QDir dir(tr(".cache/%1").arg(QString::number(id)));
		if (dir.exists()) {
			dir.removeRecursively();
		}
	};

	std::function<void(bool)> rcvCB = [this, index, id](bool)
	{
		char buffer[128]{ 0 };
		sprintf(buffer, "update Memo set IN_RECYCLE=0 where ID=%u", id);

		ExecSQL(db, buffer);
		ui.cycleWidget->takeItem(index.row());
	};

	connect(delAction, &QAction::triggered, this, delCB);
	connect(rcvAction, &QAction::triggered, this, rcvCB);

	auto p = ui.cycleWidget->cursor().pos();
	p = mapFromGlobal(p);
	menu.exec(mapToGlobal(p - QPoint(50, 0)));
	*/
}

void LxMemo::onExchangePanel()
{
	int ind = ui.stackedWidget->currentIndex();
	ind++;
	ind %= 2;
	ui.stackedWidget->SetCurrentIndex(ind);

	auto button = qobject_cast<QToolButton*>(sender());
	if (button) {
		if (ind == 1) {
			button->setIcon(QIcon(":/LxMemo/icons/symbol.png"));
			button->setToolTip(tr("Memos"));
		}
		else {
			button->setIcon(QIcon(":/LxMemo/icons/recycle-fill.png"));
			button->setToolTip(tr("Recycle"));
		}
	}

	//recycle
	//FIXME: 可能效率会比较低
	//if (ind == 1) {
	//    ui.cycleWidget->clear();
	//    initRecycleMemo();
	//}
	//else {
	ui.listWidget->clear();
	initDB();
	//}
}

void LxMemo::onWindowClosed()
{
	if (_opendDlg.isEmpty())
		close();
}

void LxMemo::onRecycleItemEdit(const QModelIndex& index)
{
	/*
	auto item = ui.cycleWidget->item(index.row());
	auto p = ui.cycleWidget->cursor().pos();
	auto rect = ui.cycleWidget->visualItemRect(item);
	p = mapFromGlobal(p);

	_cc->hide();

	auto tR = rect.topRight();
	auto r = QRect(tR - QPoint(25, -50), tR - QPoint(5, -60));
	if (r.contains(p)) {
		editRecycleItem(index);
	}
	*/
}

void LxMemo::onDeleteMemo(const QPoint& pos)
{
	auto index = ui.listWidget->indexAt(pos);
	if (index.isValid()) {
		auto p = ui.listWidget->mapToGlobal(pos);

		editItem(index, p);
	}
	else {
		QMenu menu;
		auto addAct = menu.addAction(QIcon(":/LxMemo/icons/add.png"), "New");
		auto importAction = menu.addAction(QIcon(":/LxMemo/icons/import.png"), tr("Import"));
		auto addFolderAction = menu.addAction(QIcon(":/LxMemo/icons/mini-folder.png"), "New Folder");
		auto pastAction = menu.addAction(QIcon(":/LxMemo/icons/paste.png"), tr("Paste Memo"));

		if (!_cutMeta)
			pastAction->setEnabled(false);

		std::function<void(bool)> importHtml = [this](bool)
		{
			auto htmlFile = QFileDialog::getOpenFileName(nullptr, tr("Open"), QString(), "*.html;*.txt");
			if (htmlFile.isEmpty())
				return;

			QFile f(htmlFile);
			f.open(QIODevice::ReadOnly);
			if (f.isOpen()) {
				auto content = f.readAll();
				f.close();

				auto memo = SharedMemo(new Memo());
				memo->SetHtml(content);
				addMemo(memo);

				auto content_base = QString(content).toLocal8Bit().toBase64();
				auto snap = memo->Snapshot().toLocal8Bit().toBase64();
				std::unique_ptr<char> data(new char[content_base.length() + snap.length() + 256] { 0 });
				int r = sprintf(data.get(), R"(update Memo set DATA="%s", SNAPSHOT="%s" where ID=%u;)",
					content_base.data(),
					snap.data(),
					memo->Id());

				ExecSQL(db, data.get());
				onUpdateMemo(memo->Id());
			}
		};

		std::function<void(bool)> pasteMemo = [this](bool)
		{
			if (_cutMeta) {
				auto sql = tr("update Memo set PPATH=\"%1\" where ID=%2;")
					.arg(_path.path(), QString::number(_cutMeta->Id()));
				bool ret = ExecSQL(db, sql.toLocal8Bit().data());
				if (ret) {
					///先删除，后添加
					if (_cutItem.isValid()) {
						ui.listWidget->takeItem(_cutItem.row());
						_cutItem = QModelIndex();
					}

					loadMeta(_cutMeta, "MEMO");
				}

				_cutMeta = nullptr;
			}
		};

		connect(addAct, &QAction::triggered, this, &LxMemo::onAddMemo);
		connect(importAction, &QAction::triggered, this, importHtml);
		connect(addFolderAction, &QAction::triggered, this, &LxMemo::onAddFolder);
		connect(pastAction, &QAction::triggered, this, pasteMemo);

		menu.exec(mapToGlobal(pos));
	}
}

/// <summary>
/// 对memo进行编辑，忽略文件夹节点
/// </summary>
/// <param name="index"></param>
void LxMemo::onItemEdit(const QModelIndex& index)
{
	auto item = ui.listWidget->item(index.row());
	auto type = item->data(1).toString();
	if (type == "FOLDER")
		return;

	auto p = cursor().pos();
	auto rect = ui.listWidget->visualItemRect(item);
	p = mapFromGlobal(p);
	p = ui.listWidget->mapFrom(this, p);

	_cc->hide();

	auto tR = rect.topRight();
	auto r = QRect(tR - QPoint(30, -8), tR - QPoint(9, -21));
	if (r.contains(p)) {
		auto pos = ui.listWidget->mapToGlobal(r.bottomLeft());
		editItem(index, pos);
	}
}

///在编辑memo后，更新主界面memo的snapshot
void LxMemo::onUpdateMemo(uint32_t id)
{
	QListWidgetItem* item = nullptr;
	for (int i = 0; i < ui.listWidget->count(); i++)
		if (ui.listWidget->item(i)->data(Qt::UserRole).toUInt() == id) {
			item = ui.listWidget->item(i);
			break;
		}
	if (item) {
		auto meta = qvariant_cast<SharedMeta>(item->data(0));
		///FIXME: 设置为0，为了是使界面能够重新计算每个Item的rect
		///如果有其它方法，需要将这里的代码删除
		/// note：可能会产生bug
		item->setData(0, 0);
		item->setData(0, QVariant::fromValue(meta));
	}

	ui.listWidget->viewport()->repaint();
}

void LxMemo::onMemoClosed()
{
	auto obj = qobject_cast<LucencyDialog*>(sender());
	auto mid = obj->Widget<MemoDialog*>()->MemoId();
	_opendDlg.remove(mid);

	/// <summary>
	/// 如果当前的主界面已经隐藏，且无打开的memo，则关闭软件
	/// </summary>
	if (_opendDlg.isEmpty()) {
		if (isHidden())
			close();
	}
}

void LxMemo::onBack()
{
	if (!_path.isRoot()) {
		_path = _path.parent();
		ui.label->setText(_path.path());

		ui.listWidget->clear();
		queryData(_path);

		if (_path.isRoot())
			ui.button_back->setEnabled(false);
	}
}

void LxMemo::onForward()
{
}

void LxMemo::onAddFolder()
{
	auto endpos = mapToGlobal(QPoint(10, height() / 2 - 30));
	auto startpos = mapToGlobal(QPoint(10, height() / 2 - 30));

	LucencyDialog* dlg = new LucencyDialog(this);
	FolderCreator* creator = new FolderCreator(dlg);
	dlg->setWindowModality(Qt::WindowModal);
	dlg->SetPureStyle("rgb(235,229,209)");
	dlg->setAttribute(Qt::WA_DeleteOnClose);
	//dlg->SetToolBarVisible(false);
	dlg->SetFixedEnable(false);
	dlg->SetAttribute(~WA_MINIMUM_WINDOW & ~WA_MAXIMUM_WINDOW);
	dlg->SetWidget(creator);
	dlg->show();

	StartOpacityAnimation(dlg, 0, 1);
	StartGeometryAnimation(dlg,
		QRect(startpos, QSize(width() - 20, 10)),
		QRect(endpos, QSize(width() - 20, 60)),
		QEasingCurve::Linear, 100);

	connect(creator, SIGNAL(windowClosed()), dlg, SLOT(close()));
	int ok = creator->exec();
	if (ok == QDialog::Accepted)
	{
		auto name = creator->getText();

		if (!name.isEmpty()) {
			auto folder = SharedFolder(new Folder());
			folder->SetTime(QDateTime::currentDateTime().toString());
			folder->setName(name);

			char buffer[512]{ 0 };
			auto time = QDateTime::currentDateTime().toString();
			auto path = _path;
			path += name;

			sprintf(buffer,
				R"(insert into Memo (ID, PROP, IN_RECYCLE, TIME, PATH, PPATH, TYPE) values(%u,"%s", 0, "%s", "%s", "%s", "FOLDER");)",
				folder->Id(), folder->PropertyToStream().data(), time.toLocal8Bit().data(), path.path().toLocal8Bit().data(),
				_path.path().toLocal8Bit().data());

			bool ret = ExecSQL(db, buffer);
			if (ret) {
				auto item = new QListWidgetItem();
				item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);
				item->setData(0, QVariant::fromValue((SharedMeta)folder));
				item->setData(1, "FOLDER");
				ui.listWidget->insertItem(0, item);
			}
		}
	}
}

void LxMemo::onEditFinished(uint32_t id, const QString& last, const QString& curr)
{
	auto oldpath = _path;
	oldpath += last;

	auto path = _path;
	path += curr;

	auto sql = tr("update Memo set PATH='%1' where ID=%2;").arg(path.path().data(), QString::number(id));
	bool ret = ExecSQL(db, sql.toLocal8Bit().data());

	if (ret) {
		sql = tr("update Memo set PPATH=replace(PPATH, '%1', '%2');")
			.arg(oldpath.path(), path.path());
		ExecSQL(db, sql.toLocal8Bit().data());
	}
}

void LxMemo::loadMeta(SharedMeta meta, const QString& type)
{
	QListWidgetItem* item = new QListWidgetItem();
	if ("FOLDER" == type)
		item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);
	item->setData(0, QVariant::fromValue(meta));
	item->setData(1, type);
	item->setData(Qt::UserRole, meta->Id());
	ui.listWidget->insertItem(0, item);
}

void LxMemo::loadRecyleMemo(SharedMeta memo)
{
	/*
	QListWidgetItem* item = new QListWidgetItem();
	item->setData(0, QVariant::fromValue(memo));
	item->setData(Qt::UserRole, memo->Id());
	ui.cycleWidget->insertItem(0, item);
	*/
}

int onReadDataFromDB(void* lx, int rows, char** rowData, char** colNames)
{
	auto lxmemo = (LxMemo*)lx;

	uint32_t id = std::stoull(rowData[0]);
	QByteArray prop = rowData[1];
	QString snapshot = QString::fromLocal8Bit(QByteArray::fromBase64(rowData[2]));
	QString time = QString::fromLocal8Bit(rowData[3]);
	QString type = rowData[4];
	QString path = QString::fromLocal8Bit(rowData[5]);

	if (type == "FOLDER") {
		auto meta = SharedFolder(new Folder(id));
		QDir dir(path);
		meta->setName(dir.dirName());
		meta->SetTime(time);
		meta->StreamToProperty(prop);

		lxmemo->loadMeta(meta, "FOLDER");
	}
	else {
		auto memo = SharedMemo(new Memo(id));
		memo->SetSnapshot(snapshot);
		memo->StreamToProperty(prop);
		memo->SetTime(time);

		lxmemo->loadMeta(memo, "MEMO");
	}
	return 0;
}

void LxMemo::queryData(const Path& path)
{
	auto sql = tr(R"(select ID, PROP, SNAPSHOT, TIME, TYPE, PATH from Memo where PPATH="%1" and IN_RECYCLE=0;)").arg(path.path());
	ExecSQL(db, sql.toLocal8Bit().toStdString().c_str(), onReadDataFromDB, this);
}

void LxMemo::exportHtml(SharedMemo memo)
{
	auto htmlFile = QFileDialog::getSaveFileName(nullptr, tr("Save"), QString(), tr("HTML(*.html);;MarkDown(*.md)"));
	if (htmlFile.isEmpty())
		return;

	QFileInfo finfo(htmlFile);
	auto suffx = finfo.completeSuffix();

	QFile file(htmlFile);
	file.open(QIODevice::WriteOnly);
	if (file.isOpen()) {
		if (suffx == "md")
			file.write(memo->GetMarkdown().toUtf8());
		else
			file.write(memo->GetHtml().toUtf8());
		file.close();
	}
}

void LxMemo::initDB()
{
	db = NewSqlite3Handle("memo.db");
	char* szErrMsg = 0;

	auto sql = R"(
        CREATE TABLE IF NOT EXISTS Memo(
            ID BIGINT PRIMARY KEY NOT NULL,
            DATA TEXT,
            PROP TEXT,
            IN_RECYCLE INTEGER,
            SNAPSHOT TEXT,
            TIME TEXT,
            PATH TEXT,
            PPATH TEXT,
            TYPE TEXT);
    )";
	ExecSQL(db, sql);

	//sql = "select ID, DATA, PROP from Memo where IN_RECYCLE=0;";
	//sql = R"(select ID, PROP, SNAPSHOT, TIME, TYPE, PATH from Memo where PPATH="/";)";
	//ExecSQL(db, sql, onReadDataFromDB, this);

	queryData(Path("/"));
}

int onReadCycleMemo(void* lx, int rows, char** rowData, char** colNames)
{
	/*
	auto lxmemo = (LxMemo*)lx;

	uint32_t id = std::stoull(rowData[0]);
	QByteArray prop = rowData[1];
	QString snapshot = QString::fromLocal8Bit(QByteArray::fromBase64(rowData[2]));
	QString time = QString::fromLocal8Bit(rowData[3]);

	auto memo = SharedMemo(new Memo(id));
	memo->SetSnapshot(snapshot);
	memo->StreamToProperty(prop);
	memo->SetTime(time);

	lxmemo->loadRecyleMemo(memo);
	*/
	return 0;
}

void LxMemo::initRecycleMemo()
{
	const char* sql = "select ID, PROP, SNAPSHOT, TIME from Memo where IN_RECYCLE=1;";
	ExecSQL(db, sql, onReadCycleMemo, this);
}

void LxMemo::showMemo(SharedMemo memo)
{
	auto fontDlg = QSharedPointer<LucencyDialog>(new LucencyDialog());

	auto backAction = fontDlg->AddAction(QIcon(":/LxMemo/icons/back_home.png"), tr("返回列表"));
	fontDlg->SetOpacity(0);
	fontDlg->SetPureStyle(memo->GetColor().name(QColor::HexArgb));
	fontDlg->SetIcon("", false);
	fontDlg->SetAttribute(~WA_MAXIMUM_WINDOW);

	MemoDialog* dlg = new MemoDialog(memo, db);
	auto title = QString::fromLocal8Bit("ID:%1").arg(memo->Id());
	dlg->setWindowTitle(title);
	fontDlg->setWindowTitle(title);
	dlg->SetMemo(memo);

	uint32_t id = memo->Id();
	_opendDlg.insert(memo->Id(), fontDlg);
	fontDlg->SetWidget(dlg);
	fontDlg->resize(400, 350);

	srand(time(nullptr));
	auto TR = rect().topRight();
	TR = mapToGlobal(TR);

	TR.rx() += rand() % 200;
	TR.ry() += rand() % 150;

	fontDlg->move(TR);

	fontDlg->show();

	connect(backAction, &QToolButton::clicked, this, &LxMemo::ReDisplay);
	connect(fontDlg.data(), &LucencyDialog::windowClosed, dlg, &MemoDialog::onWindowClosed);
	connect(fontDlg.data(), &LucencyDialog::windowClosed, this, &LxMemo::onMemoClosed);
	connect(dlg, &MemoDialog::MemoUpdate, this, &LxMemo::onUpdateMemo, Qt::QueuedConnection);

	StartOpacityAnimation(fontDlg.get(), 0, 0.95);
}

void LxMemo::onEditMemo(const QModelIndex& index)
{
	//auto item = ui.listWidget->item(index.row());
	auto meta = qvariant_cast<SharedMeta>(index.data());

	if (index.data(1).toString() == "FOLDER")
	{
		auto folder = qSharedPointerCast<Folder>(meta);
		//auto path = _path;
		_path += folder->name();

		ui.label->setText(_path.path());
		ui.listWidget->clear();
		ui.button_back->setEnabled(true);

		queryData(_path);

		_cutItem = QModelIndex();
	}
	else {
		auto isShow = _opendDlg.contains(meta->Id());
		if (isShow)
			return;

		auto memo = qSharedPointerCast<Memo>(meta);
		if (memo->GetHtml().isEmpty()) {
			auto sql = QString("select DATA from Memo where ID=%1").arg(QString::number(memo->Id()));

			MemoContext ctx = { this, memo , [](LxMemo* lm, SharedMemo memo) {lm->showMemo(memo); } };
			ExecSQL(db, sql.toUtf8().data(), loadMemoData, &ctx);
		}
		else
			showMemo(memo);
	}
}

bool LxMemo::eventFilter(QObject* object, QEvent* event)
{
	if (object == ui.listWidget) {
		if (event->type() == QEvent::Resize) {
			if (!_cc->isHidden()) {
				QResizeEvent* ev = (QResizeEvent*)event;
				_cc->move(0, ui.listWidget->height());
				_cc->resize(width(), _cc->height());
			}
		}
	}
	return QWidget::eventFilter(object, event);
}